import java.awt.event.ActionEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

/**
 * The file menu controller listens to the BrickFrame and executes
 * when a menu item in the File MenuBar is selected. Private methods
 * are implemented to save, open, exit and save as.
 * @author Sophia Soohoo
 *
 */
public class FileMenuController extends BrickController{

	private File currentDirectory = new File("C:/");

	/**
	 * The only constructor, which takes a BrickFrame or any
	 * subclass there of
	 * @param frame  the frame which contains the file menu
	 */
	public FileMenuController(BrickFrame frame) {
		super(frame);
	}
	
	
	/**
	 * @return the currentDirectory
	 */
	public File getCurrentDirectory() {
		return currentDirectory;
	}

	
	/**
	 * @param currentDirectory the currentDirectory to set
	 */
	public void setCurrentDirectory(File currentDirectory) {
		this.currentDirectory = currentDirectory;
	}
	
	/**
	 * Private set method takes a current directory from JFileChooser
	 * @param js  the JFileChooser which contains the user's selection
	 */
	private void setCurrentDirectory(JFileChooser js) {
	    setCurrentDirectory(js.getSelectedFile().getParentFile());
	}
	
	/**
	 * Clears the undo and redo stack in the command processor
	 */
	private void clearUndoRedo() {
        //Clear both stacks 
        this.getFrame().getCommandProcessor().clearRedo();
        this.getFrame().getCommandProcessor().clearUndo();
	}
	
	/**
	 * Takes the JFileChooser and extracts the object that the user
	 * has selected
	 * @param js  The JFileChooser which user has selected a file from
	 * @return    The object contained in that file 
	 * @throws ClassNotFoundException  throws if the class of the object is
	 *                                 not found
	 * @throws IOException  throws if the file cannot be opened
	 * @throws BrickException 
	 */
	private void  loadObjectFromFile(JFileChooser js) throws 
	    ClassNotFoundException, IOException, BrickException {
	    
	    FileInputStream fis = new FileInputStream(js.getSelectedFile());
        ObjectInputStream in = new ObjectInputStream(fis);    
        Object o = in.readObject();
        
      //if the object read in is a brickmodel, read in
        if (o instanceof BrickModel) {                  
            BrickModel newModel = new BrickModel((BrickModel)o);                    
            getModel().setModel(newModel);
        }
	}
	
	/**
	 * Private helper function. Asks the user for inputfile. Loads
	 * the BrickModel if it exists and a valid file is chosen.
	 * @throws ClassNotFoundException 
	 */
	private void open() throws ClassNotFoundException {
		
		JFileChooser js = new JFileChooser();
		
		//if current directory is not null, open JFilechooser using the current
		//directory last saved by the controller
		if (currentDirectory != null) 
		    js.setCurrentDirectory(currentDirectory);
		
		//display the view for the user to select
		int val = js.showOpenDialog(null);
		
		//follow if you choose to open the model
		if (val == JFileChooser.APPROVE_OPTION) {
			try {				
			    
			    loadObjectFromFile(js);				
				setCurrentDirectory(js);
				
				//clear the stacks, close all views and set changed = false
				clearUndoRedo();
				getFrame().closeAllViews();
                getModel().setChanged(false);
                
                //Set the name of the Frame to the saved file
                this.getFrame().setTitle("BrickCAD " + js.getName(js.getSelectedFile()));
				
			} catch (IOException e) {
                JOptionPane.showMessageDialog(null, 
                        "File could not be opened or wrong file type");
            } catch (BrickException b){
            	System.err.println(b.getMessage());
            }
		}
	}	

	
	/**
	 * Exits the program. If the model has changed since the last save
	 * the program will prompt the user to save again. If the user selects
	 * yes, save() will be run. If the user chooses no, the program exits.
	 * If the user chooses cancel, return to program.
	 */
	private void exit() {
			    
	    //if the model has not changed, close immediately
		if (!getModel().isChanged()) {
			System.exit(0);
			
			//if the model has changed
		} else {
		    
		    //prompt for a save
		    int val = JOptionPane.showConfirmDialog(null, 
		    "Do you want to save changes to current model?");

	          //if the user chooses no, exit
		    if (val == JOptionPane.NO_OPTION) System.exit(0);
		    
		    //if the user chooses to cancel, return to screen
		    if (val == JOptionPane.CANCEL_OPTION) return;
		       
		    //if the user chooses save, then save or saveAs as needed		    
		    if (getModel().getFile() != null) {
		        save(false);		    
		    } else {
		        save(true);
		    }
		}
	}
	
	/**
	 * Private helper method saves the BrickModel to a particular
	 * file which is either stored in the BrickModel or picked up the
	 * user
	 * @param saveAs if user should choose the file
	 */
	private void save(boolean saveAs) {
		
	  //if there is no current file or the user chooses save as option
        //ask for the file
        if ((saveAs == true) || (getModel().getFile() == null)) {
            
            
            JFileChooser fc = new JFileChooser();   
         
            
            
            
            //if there is a current directory stored in controller, use it
            if (currentDirectory != null) fc.setCurrentDirectory
                (currentDirectory);
            
            //ask user for file to save to and destination
            int val = fc.showSaveDialog(null);
            
            //if the user does not choose a file, continue application
            if(val != JFileChooser.APPROVE_OPTION) return;
            
            //set the file in the model to the one provided by user
            getModel().setFile(fc.getSelectedFile());
            
            //Set the name of the Frame to the saved file
            this.getFrame().setTitle("BrickCAD " + fc.getName(fc.getSelectedFile()));
            
            setCurrentDirectory(fc);
        }
        
        //save the model and save the current working directory in controller
        getModel().save();
        
        //clear the stacks
        //clearUndoRedo();
        
	}
	
	/**
	 * Private helper method creates a new default model
	 * @throws BrickException  throws if the model receives bad height, width or height
	 */
	private void newModel() throws BrickException {
	    
		this.getFrame().setTitle("BrickCAD");
		
	    if (getModel().isChanged()) {
	        
	        int val = JOptionPane.showConfirmDialog(null, 
	                "Save changes before opening new model?");
	        
	        //if the user chooses to save
	        if (val == JOptionPane.OK_OPTION) {
	            if (getModel().getFile() != null) {
	                save(false);
	            } else {
	                save(true);
	            }
	        }
		    if(val == JOptionPane.OK_CANCEL_OPTION) return;
        }

	    //create a new model and set the changes
	    getModel().setModel(new BrickModel(null, false, 1,1,1));
        
        //Clear both stacks and close all views
        clearUndoRedo();
        getFrame().closeAllViews();
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {

	    
	    try {
	        String b = e.getActionCommand().toLowerCase().trim();
	        
	        //choose actions based on the label of the menu item
	        //and handle or throw to the appropriate method.
	        if(b.equals("exit")) {
	            exit();
	        } else if (b.equals("open")) {
	            try {
	                open();
	            } catch (ClassNotFoundException e1) {
	                e1.printStackTrace();
	            }
	        } else if (b.equals("save")) {
	            save(false);
	        } else if (b.equals("saveas")) {
	            save(true);
	        } else if (b.equals("new")){
	            newModel();
	        } else {
	            System.err.print("Bad selection. Please try again");
	        }
	        
	    } catch (BrickException a) {
	        JOptionPane.showMessageDialog(null, a.getMessage());
	    }
	}	
	
	/**
	 * to String
	 */
	public String toString(){
		return "File Menu Controller";
	}

}
